package Executror;

import cn.hutool.core.thread.NamedThreadFactory;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;

import java.util.Iterator;
import java.util.concurrent.*;

/**
 * @author : ZhuQi
 * @version : 时间:2022/8/2 11:11 版本:
 * 测试线程池拒绝策略 + 自定义拒绝策略
 */
public class ThreadPoolPolicyDemo {

    /**
     * 自定义拒绝策略任务存放容器
     */
    static final CopyOnWriteArrayList policySet = new CopyOnWriteArrayList<Runnable>();

    /**
     * 线程池
     */
    private final ThreadPoolExecutor threadPool = new ThreadPoolExecutor(1, 2, 5, TimeUnit.SECONDS,
            new LinkedBlockingDeque<>(1), new NamedThreadFactory("td-", false));

    @AfterEach
    public void doShoutDownThreadPool() throws Exception {
        while (policySet.size() != 0) {
            checkPolicyList();
        }
        threadPool.shutdown();
        while (!threadPool.isTerminated()) {
            TimeUnit.SECONDS.sleep(1);
        }
        System.out.println("任务执行完成");
    }

    private void checkPolicyList() {
        System.out.println("当前任务：" + policySet.size());
        for (int i = 0; i < policySet.size(); i++) {
            Runnable target = (Runnable) policySet.get(i);
            threadPool.execute(target);
            policySet.remove(i);
        }
    }

    /**
     * 测试内容: AbortPolicy 默认拒绝策略:拒绝任务并抛出任务
     * 测试结果: 抛出了任务但是不能使用，因为抛出的是Runable.toString 具体输出如下：
     * Task Executror.ThreadPoolPolicyDemo$$Lambda$305/2131952342@37918c79
     * rejected from java.util.concurrent.ThreadPoolExecutor@78e94dcf
     * [Running, pool size = 2, active threads = 0, queued tasks = 0, completed tasks = 3]
     */
    @Test
    public void test01() throws Exception {
        threadPool.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
        for (int i = 0; i < 10; i++) {
            try {
                threadPool.execute(() -> System.out.println(Thread.currentThread().getName()));
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }
    }


    /**
     * 测试内容: CallerRunsPolicy 使用调用线程执行任务
     * 测试结果: 输出了main线程的名称,线程池触发拒绝策略后，由调用线程执行任务
     */
    @Test
    public void test02() throws Exception {
        threadPool.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        for (int i = 0; i < 10; i++) {
            try {
                threadPool.execute(() -> System.out.println(Thread.currentThread().getName()));
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }
    }

    /**
     * 测试内容: DiscardPolicy 直接拒绝任务，不抛出错误
     * 测试结果: 只执行了三个任务便停止了
     */
    @Test
    public void test03() throws Exception {
        threadPool.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
        for (int i = 0; i < 10; i++) {
            try {
                threadPool.execute(() -> System.out.println(Thread.currentThread().getName()));
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }
    }

    /**
     * 测试内容: DiscardOldestPolicy 触发拒绝策略，只要还有任务新增，一直会丢弃阻塞队列的最老的任务，并将新的任务加入
     * 测试结果: 也只执行了三个任务便停止了
     */
    @Test
    public void test04() throws Exception {
        threadPool.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
        for (int i = 0; i < 10; i++) {
            try {
                threadPool.execute(() -> System.out.println(Thread.currentThread().getName()));
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }
    }


    /**
     * 测试内容: 自定义拒绝策略
     * 测试结果:
     */
    @Test
    public void test05() throws Exception {
        threadPool.setRejectedExecutionHandler(new MyThreadPoolPolicyDemo());
        for (int i = 0; i < 10; i++) {
            try {
                threadPool.execute(() -> System.out.println(Thread.currentThread().getName()));
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
        }


    }
}

/**
 * 自定义拒绝策略
 */
class MyThreadPoolPolicyDemo implements RejectedExecutionHandler {

    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        System.out.println("触发拒绝策略，存入某个容器等待以后执行");
        ThreadPoolPolicyDemo.policySet.add(r);
    }
}